(Feature) Add voting to manage emission funds

This commit is contained in:
Vadim Arasev 2018-09-17 19:17:56 +03:00
parent 12719ebd8c
commit 5639487713
16 changed files with 645 additions and 154 deletions

File diff suppressed because one or more lines are too long

View File

@ -136,4 +136,12 @@ button {
padding-top: 12px; padding-top: 12px;
margin: 0; margin: 0;
word-break: break-word; word-break: break-word;
a {
color: $primary-color;
.sokol & {
color: $primary-color-sokol;
}
}
} }

View File

@ -8,6 +8,9 @@ import swal from 'sweetalert2'
const ACCEPT = 1 const ACCEPT = 1
const REJECT = 2 const REJECT = 2
const SEND = 1
const BURN = 2
const FREEZE = 3
const USDateTimeFormat = 'MM/DD/YYYY h:mm:ss A' const USDateTimeFormat = 'MM/DD/YYYY h:mm:ss A'
const maxDetailsLength = 500 const maxDetailsLength = 500
@ -102,6 +105,60 @@ export class BallotCard extends React.Component {
return votesPercents return votesPercents
} }
@computed
get votesBurnNumber() {
let votes = this.burnVotes
if (isNaN(votes)) votes = 0
return votes
}
@computed
get votesBurnPercents() {
if (this.totalVoters <= 0) {
return 0
}
let votesPercents = Math.round((this.votesBurnNumber / this.totalVoters) * 100)
if (isNaN(votesPercents)) votesPercents = 0
return votesPercents
}
@computed
get votesFreezeNumber() {
let votes = this.freezeVotes
if (isNaN(votes)) votes = 0
return votes
}
@computed
get votesFreezePercents() {
if (this.totalVoters <= 0) {
return 0
}
let votesPercents = Math.round((this.votesFreezeNumber / this.totalVoters) * 100)
if (isNaN(votesPercents)) votesPercents = 0
return votesPercents
}
@computed
get votesSendNumber() {
let votes = this.sendVotes
if (isNaN(votes)) votes = 0
return votes
}
@computed
get votesSendPercents() {
if (this.totalVoters <= 0) {
return 0
}
let votesPercents = Math.round((this.votesSendNumber / this.totalVoters) * 100)
if (isNaN(votesPercents)) votesPercents = 0
return votesPercents
}
@action('Calculate time to start/finish') @action('Calculate time to start/finish')
calcTimeTo = () => { calcTimeTo = () => {
const _now = moment() const _now = moment()
@ -202,8 +259,18 @@ export class BallotCard extends React.Component {
async tx => { async tx => {
const ballotInfo = await contract.getBallotInfo(id, contractsStore.votingKey) const ballotInfo = await contract.getBallotInfo(id, contractsStore.votingKey)
this.totalVoters = Number(ballotInfo.totalVoters) if (ballotInfo.hasOwnProperty('totalVoters')) {
this.progress = Number(ballotInfo.progress) this.totalVoters = Number(ballotInfo.totalVoters)
} else {
this.burnVotes = ballotInfo.burnVotes
this.freezeVotes = ballotInfo.freezeVotes
this.sendVotes = ballotInfo.sendVotes
this.totalVoters =
Number(ballotInfo.burnVotes) + Number(ballotInfo.freezeVotes) + Number(ballotInfo.sendVotes)
}
if (ballotInfo.hasOwnProperty('progress')) {
this.progress = Number(ballotInfo.progress)
}
this.isFinalized = Boolean(ballotInfo.isFinalized) this.isFinalized = Boolean(ballotInfo.isFinalized)
if (ballotInfo.hasOwnProperty('canBeFinalizedNow')) { if (ballotInfo.hasOwnProperty('canBeFinalizedNow')) {
this.canBeFinalized = Boolean(ballotInfo.canBeFinalizedNow) this.canBeFinalized = Boolean(ballotInfo.canBeFinalizedNow)
@ -212,8 +279,16 @@ export class BallotCard extends React.Component {
} }
this.hasAlreadyVoted = true this.hasAlreadyVoted = true
ballotsStore.ballotCards[pos].props.votingState.totalVoters = this.totalVoters if (ballotInfo.hasOwnProperty('totalVoters')) {
ballotsStore.ballotCards[pos].props.votingState.progress = this.progress ballotsStore.ballotCards[pos].props.votingState.totalVoters = this.totalVoters
} else {
ballotsStore.ballotCards[pos].props.votingState.burnVotes = this.burnVotes
ballotsStore.ballotCards[pos].props.votingState.freezeVotes = this.freezeVotes
ballotsStore.ballotCards[pos].props.votingState.sendVotes = this.sendVotes
}
if (ballotInfo.hasOwnProperty('progress')) {
ballotsStore.ballotCards[pos].props.votingState.progress = this.progress
}
ballotsStore.ballotCards[pos].props.votingState.isFinalized = this.isFinalized ballotsStore.ballotCards[pos].props.votingState.isFinalized = this.isFinalized
ballotsStore.ballotCards[pos].props.votingState.canBeFinalized = this.canBeFinalized ballotsStore.ballotCards[pos].props.votingState.canBeFinalized = this.canBeFinalized
ballotsStore.ballotCards[pos].props.votingState.hasAlreadyVoted = this.hasAlreadyVoted ballotsStore.ballotCards[pos].props.votingState.hasAlreadyVoted = this.hasAlreadyVoted
@ -315,6 +390,8 @@ export class BallotCard extends React.Component {
return contractsStore.votingToChangeMinThreshold return contractsStore.votingToChangeMinThreshold
case 'votingToChangeProxy': case 'votingToChangeProxy':
return contractsStore.votingToChangeProxy return contractsStore.votingToChangeProxy
case 'votingToManageEmissionFunds':
return contractsStore.votingToManageEmissionFunds
case 'validatorMetadata': case 'validatorMetadata':
return contractsStore.validatorMetadata return contractsStore.validatorMetadata
default: default:
@ -330,6 +407,8 @@ export class BallotCard extends React.Component {
return contractsStore.minThresholdBallotThreshold return contractsStore.minThresholdBallotThreshold
case 'votingToChangeProxy': case 'votingToChangeProxy':
return contractsStore.proxyBallotThreshold return contractsStore.proxyBallotThreshold
case 'votingToManageEmissionFunds':
return contractsStore.emissionFundsBallotThreshold
default: default:
return contractsStore.keysBallotThreshold return contractsStore.keysBallotThreshold
} }
@ -346,9 +425,18 @@ export class BallotCard extends React.Component {
this.creator = votingState.creator this.creator = votingState.creator
this.creatorMiningKey = votingState.creatorMiningKey this.creatorMiningKey = votingState.creatorMiningKey
// getTotalVoters // getTotalVoters
this.totalVoters = Number(votingState.totalVoters) if (votingState.hasOwnProperty('totalVoters')) {
this.totalVoters = Number(votingState.totalVoters)
} else {
this.burnVotes = Number(votingState.burnVotes)
this.freezeVotes = Number(votingState.freezeVotes)
this.sendVotes = Number(votingState.sendVotes)
this.totalVoters = this.burnVotes + this.freezeVotes + this.sendVotes
}
// getProgress // getProgress
this.progress = Number(votingState.progress) if (votingState.hasOwnProperty('progress')) {
this.progress = Number(votingState.progress)
}
// getIsFinalized // getIsFinalized
this.isFinalized = votingState.isFinalized this.isFinalized = votingState.isFinalized
// canBeFinalizedNow // canBeFinalizedNow
@ -397,6 +485,8 @@ export class BallotCard extends React.Component {
return 'Keys' return 'Keys'
case 'votingToChangeProxy': case 'votingToChangeProxy':
return 'Proxy' return 'Proxy'
case 'votingToManageEmissionFunds':
return 'EmissionFunds'
default: default:
return '' return ''
} }
@ -425,66 +515,25 @@ export class BallotCard extends React.Component {
) : ( ) : (
'' ''
) )
return ( let votingScale
<div className={ballotClass}> if (votingType === 'votingToManageEmissionFunds') {
<div className="ballots-about"> votingScale = (
<div className="ballots-about-i ballots-about-i_name"> <div className="ballots-i-scale">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Proposer</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p className="ballots-i--name">{this.creator}</p>
</div>
</div>
{children}
<div className="ballots-about-i ballots-about-i_time">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Ballot Time</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p className="ballots-i--created">{this.startTime}</p>
<p className="ballots-i--time">
{this.timeTo.displayValue}&nbsp;({this.timeTo.title})
</p>
</div>
</div>
</div>
{/* TODO: Send / Burn / Freeze */}
{/* <div className="ballots-i-scale">
<div className="ballots-i-scale-column ballots-i-scale-column-3">
<button
className="btn btn-success ballots-i--vote_btn xl m-r-20"
onClick={e => this.vote({ choice: ACCEPT })}
type="button"
>
Send
</button>
<div className="vote-scale--container">
<p className="vote-scale--votes">{this.votesForNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesForPercents}%</p>
<div className={voteScaleClass}>
<div
className="vote-scale--fill vote-scale--fill_send"
style={{ width: `${this.votesForPercents}%` }}
/>
</div>
</div>
</div>
<div className="ballots-i-scale-column ballots-i-scale-column-3"> <div className="ballots-i-scale-column ballots-i-scale-column-3">
<button <button
type="button" type="button"
onClick={e => this.vote({ choice: REJECT })} onClick={e => this.vote({ choice: BURN })}
className="btn btn-danger ballots-i--vote_btn xl m-r-20" className="btn btn-danger ballots-i--vote_btn xl m-r-20"
> >
Burn Burn
</button> </button>
<div className="vote-scale--container"> <div className="vote-scale--container">
<p className="vote-scale--votes">{this.votesAgainstNumber} Votes</p> <p className="vote-scale--votes">{this.votesBurnNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesAgainstPercents}%</p> <p className="vote-scale--percentage">{this.votesBurnPercents}%</p>
<div className={voteScaleClass}> <div className={voteScaleClass}>
<div <div
className="vote-scale--fill vote-scale--fill_burn" className="vote-scale--fill vote-scale--fill_burn"
style={{ width: `${this.votesAgainstPercents}%` }} style={{ width: `${this.votesBurnPercents}%` }}
/> />
</div> </div>
</div> </div>
@ -492,24 +541,45 @@ export class BallotCard extends React.Component {
<div className="ballots-i-scale-column ballots-i-scale-column-3"> <div className="ballots-i-scale-column ballots-i-scale-column-3">
<button <button
type="button" type="button"
onClick={e => this.vote({ choice: REJECT })} onClick={e => this.vote({ choice: FREEZE })}
className="btn btn-freeze ballots-i--vote_btn xl m-r-20" className="btn btn-freeze ballots-i--vote_btn xl m-r-20"
> >
Freeze Freeze
</button> </button>
<div className="vote-scale--container"> <div className="vote-scale--container">
<p className="vote-scale--votes">{this.votesAgainstNumber} Votes</p> <p className="vote-scale--votes">{this.votesFreezeNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesAgainstPercents}%</p> <p className="vote-scale--percentage">{this.votesFreezePercents}%</p>
<div className={voteScaleClass}> <div className={voteScaleClass}>
<div <div
className="vote-scale--fill vote-scale--fill_freeze" className="vote-scale--fill vote-scale--fill_freeze"
style={{ width: `${this.votesAgainstPercents}%` }} style={{ width: `${this.votesFreezePercents}%` }}
/> />
</div> </div>
</div> </div>
</div> </div>
</div> */} <div className="ballots-i-scale-column ballots-i-scale-column-3">
{/* No / yes */} <button
className="btn btn-success ballots-i--vote_btn xl m-r-20"
onClick={e => this.vote({ choice: SEND })}
type="button"
>
Send
</button>
<div className="vote-scale--container">
<p className="vote-scale--votes">{this.votesSendNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesSendPercents}%</p>
<div className={voteScaleClass}>
<div
className="vote-scale--fill vote-scale--fill_send"
style={{ width: `${this.votesSendPercents}%` }}
/>
</div>
</div>
</div>
</div>
)
} else {
votingScale = (
<div className="ballots-i-scale"> <div className="ballots-i-scale">
<div className="ballots-i-scale-column"> <div className="ballots-i-scale-column">
<button <button
@ -547,6 +617,33 @@ export class BallotCard extends React.Component {
</button> </button>
</div> </div>
</div> </div>
)
}
return (
<div className={ballotClass}>
<div className="ballots-about">
<div className="ballots-about-i ballots-about-i_name">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Proposer</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p className="ballots-i--name">{this.creator}</p>
</div>
</div>
{children}
<div className="ballots-about-i ballots-about-i_time">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Ballot Time</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p className="ballots-i--created">{this.startTime}</p>
<p className="ballots-i--time">
{this.timeTo.displayValue}&nbsp;({this.timeTo.title})
</p>
</div>
</div>
</div>
{votingScale}
<div className="info-container"> <div className="info-container">
<div className="info info-minimum"> <div className="info info-minimum">
Minimum {threshold} from {contractsStore.validatorsLength} validators are required to pass the proposal Minimum {threshold} from {contractsStore.validatorsLength} validators are required to pass the proposal

View File

@ -0,0 +1,32 @@
import React from 'react'
import { inject, observer } from 'mobx-react'
import { BallotCard } from './BallotCard.jsx'
@inject('contractsStore')
@observer
export class BallotEmissionFundsCard extends React.Component {
render() {
let { id, votingState, pos, contractsStore } = this.props
const amount = contractsStore.web3Instance.fromWei(votingState.amount, 'ether')
return (
<BallotCard votingType="votingToManageEmissionFunds" votingState={votingState} id={id} pos={pos}>
<div className="ballots-about-i ballots-about-i_proposed_receiver">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Proposed Receiver</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p>{votingState.receiver}</p>
</div>
</div>
<div className="ballots-about-i ballots-about-i_funds_amount">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Funds Amount</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p>{amount} POA</p>
</div>
</div>
</BallotCard>
)
}
}

View File

@ -0,0 +1,120 @@
import React from 'react'
import { observable, action } from 'mobx'
import { inject, observer } from 'mobx-react'
import moment from 'moment'
@inject('ballotStore', 'contractsStore')
@observer
export class BallotEmissionFundsMetadata extends React.Component {
@observable emissionFundsBalance
@observable noActiveBallotExists
@observable beginDateTime
@observable endDateTime
@action('Get EmissionFunds balance')
getEmissionFundsBalance = async () => {
this.emissionFundsBalance = 'Loading...'
this.emissionFundsBalance = await this.props.contractsStore.emissionFunds.balance()
}
@action('Get VotingToManageEmissionFunds.noActiveBallotExists')
getNoActiveBallotExists = async () => {
this.noActiveBallotExists = await this.props.contractsStore.votingToManageEmissionFunds.noActiveBallotExists()
}
@action('Get beginDateTime and endDateTime')
getDateTimeLimits = async () => {
const { votingToManageEmissionFunds } = this.props.contractsStore
const dateTimeFormat = 'MM/DD/YYYY HH:mm'
this.beginDateTime = '...loading date...'
this.endDateTime = '...loading date...'
let emissionReleaseTime = Number(await votingToManageEmissionFunds.emissionReleaseTime())
let emissionReleaseThreshold = 0
const currentTime = Number(await votingToManageEmissionFunds.getTime())
const distributionThreshold = Number(await votingToManageEmissionFunds.distributionThreshold())
if (currentTime > emissionReleaseTime) {
emissionReleaseThreshold = Number(await votingToManageEmissionFunds.emissionReleaseThreshold())
const diff = Math.floor((currentTime - emissionReleaseTime) / emissionReleaseThreshold)
if (diff > 0) {
emissionReleaseTime += emissionReleaseThreshold * diff
}
}
const releasePlusDistribution = emissionReleaseTime + distributionThreshold
if (currentTime < releasePlusDistribution) {
this.beginDateTime = moment.unix(emissionReleaseTime).format(dateTimeFormat)
this.endDateTime = moment.unix(releasePlusDistribution).format(dateTimeFormat)
} else {
if (emissionReleaseThreshold === 0) {
emissionReleaseThreshold = Number(await votingToManageEmissionFunds.emissionReleaseThreshold())
}
const futureEmissionReleaseTime = emissionReleaseTime + emissionReleaseThreshold
this.beginDateTime = moment.unix(futureEmissionReleaseTime).format(dateTimeFormat)
this.endDateTime = moment.unix(futureEmissionReleaseTime + distributionThreshold).format(dateTimeFormat)
}
}
constructor(props) {
super(props)
this.getEmissionFundsBalance()
this.getNoActiveBallotExists()
this.getDateTimeLimits()
}
render() {
const { ballotStore, contractsStore } = this.props
let note, explorerLink
if (this.noActiveBallotExists === true) {
note = (
<p>
The ballot can be created starting from <b>{this.beginDateTime}</b> and will end on <b>{this.endDateTime}</b>.
</p>
)
} else if (this.noActiveBallotExists !== true) {
note = <p>To be able to create a new ballot, the previous ballot of this type must be finalized.</p>
}
if (contractsStore.netId === '77') {
explorerLink = `https://sokol-explorer.poa.network/account/${contractsStore.emissionFunds.address}`
} else {
explorerLink = `https://poaexplorer.com/address/${contractsStore.emissionFunds.address}`
}
return (
<div>
<div className="hidden">
<div className="left">
<div className="form-el">
<label htmlFor="receiver">Address of funds receiver</label>
<input
type="text"
id="receiver"
value={ballotStore.ballotEmissionFunds.receiver}
onChange={e => ballotStore.changeBallotMetadata(e, 'receiver', 'ballotEmissionFunds')}
/>
<p className="hint">
The address to which the funds will be sent if `Send` operation obtains the majority of votes.
</p>
</div>
</div>
<div className="right">
<div className="form-el">
<label htmlFor="amount">Current amount of funds</label>
<input type="text" id="amount" value={this.emissionFundsBalance} disabled="disabled" />
<p className="hint">
Current balance of&nbsp;
<a href={explorerLink} target="_blank">
EmissionFunds contract
</a>.
</p>
</div>
</div>
</div>
<hr />
{note}
<br />
</div>
)
}
}

View File

@ -63,23 +63,6 @@ export class BallotKeysCard extends React.Component {
</div> </div>
</div> </div>
{miningKeyDiv} {miningKeyDiv}
{/* TODO: New ballot type */}
{/* <div className="ballots-about-i ballots-about-i_proposed_receiver">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Proposed Receiver</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p>0x4432c441EE96ef387CEC496709967Be6E27f57C8</p>
</div>
</div>
<div className="ballots-about-i ballots-about-i_funds_amount">
<div className="ballots-about-td ballots-about-td-title">
<p className="ballots-about-i--title">Funds Amount</p>
</div>
<div className="ballots-about-td ballots-about-td-value">
<p>10000 POA</p>
</div>
</div> */}
</BallotCard> </BallotCard>
) )
} }

View File

@ -116,6 +116,14 @@ export class Ballots extends React.Component {
) { ) {
continue continue
} }
} else if (contractType === ballotStore.BallotType.emissionFunds) {
if (
String(votingState.receiver)
.toLowerCase()
.includes(searchTerm)
) {
continue
}
} }
ballotCards.splice(i--, 1) ballotCards.splice(i--, 1)

View File

@ -7,6 +7,7 @@ import { KeysTypes } from './KeysTypes.jsx'
import { BallotKeysMetadata } from './BallotKeysMetadata.jsx' import { BallotKeysMetadata } from './BallotKeysMetadata.jsx'
import { BallotMinThresholdMetadata } from './BallotMinThresholdMetadata.jsx' import { BallotMinThresholdMetadata } from './BallotMinThresholdMetadata.jsx'
import { BallotProxyMetadata } from './BallotProxyMetadata.jsx' import { BallotProxyMetadata } from './BallotProxyMetadata.jsx'
import { BallotEmissionFundsMetadata } from './BallotEmissionFundsMetadata.jsx'
import { messages } from '../messages' import { messages } from '../messages'
import { constants } from '../constants' import { constants } from '../constants'
import { sendTransactionByVotingKey } from '../helpers' import { sendTransactionByVotingKey } from '../helpers'
@ -44,40 +45,42 @@ export class NewBallot extends React.Component {
return false return false
} }
const minBallotDurationInHours = constants.minBallotDurationInDays * 24 if (!ballotStore.isBallotForEmissionFunds) {
const startTime = this.getStartTimeUnix() const minBallotDurationInHours = constants.minBallotDurationInDays * 24
const minEndTime = moment const startTime = this.getStartTimeUnix()
.utc() const minEndTime = moment
.add(minBallotDurationInHours, 'hours') .utc()
.format() .add(minBallotDurationInHours, 'hours')
let neededMinutes = moment(minEndTime).diff(moment(ballotStore.endTime), 'minutes') .format()
let neededHours = Math.floor(neededMinutes / 60) let neededMinutes = moment(minEndTime).diff(moment(ballotStore.endTime), 'minutes')
let duration = moment.unix(ballotStore.endTimeUnix).diff(moment.unix(startTime), 'hours') let neededHours = Math.floor(neededMinutes / 60)
let duration = moment.unix(ballotStore.endTimeUnix).diff(moment.unix(startTime), 'hours')
if (duration < 0) { if (duration < 0) {
duration = 0 duration = 0
} }
if (neededMinutes > 0) { if (neededMinutes > 0) {
neededMinutes = Math.abs(neededHours * 60 - neededMinutes) neededMinutes = Math.abs(neededHours * 60 - neededMinutes)
swal( swal(
'Warning!', 'Warning!',
messages.SHOULD_BE_MORE_THAN_MIN_DURATION(minBallotDurationInHours, duration, neededHours, neededMinutes), messages.SHOULD_BE_MORE_THAN_MIN_DURATION(minBallotDurationInHours, duration, neededHours, neededMinutes),
'warning' 'warning'
) )
commonStore.hideLoading() commonStore.hideLoading()
return false return false
} }
const twoWeeks = moment const twoWeeks = moment
.utc() .utc()
.add(14, 'days') .add(14, 'days')
.format() .format()
let exceededMinutes = moment(ballotStore.endTime).diff(moment(twoWeeks), 'minutes') let exceededMinutes = moment(ballotStore.endTime).diff(moment(twoWeeks), 'minutes')
if (exceededMinutes > 0) { if (exceededMinutes > 0) {
swal('Warning!', messages.SHOULD_BE_LESS_OR_EQUAL_14_DAYS(duration), 'warning') swal('Warning!', messages.SHOULD_BE_LESS_OR_EQUAL_14_DAYS(duration), 'warning')
commonStore.hideLoading() commonStore.hideLoading()
return false return false
}
} }
if (ballotStore.isBallotForKey) { if (ballotStore.isBallotForKey) {
@ -132,7 +135,7 @@ export class NewBallot extends React.Component {
} }
} }
let isAddress = contractsStore.web3Instance.isAddress(ballotStore.ballotProxy.proposedAddress) const isAddress = contractsStore.web3Instance.isAddress(ballotStore.ballotProxy.proposedAddress)
if (!isAddress) { if (!isAddress) {
swal('Warning!', messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG, 'warning') swal('Warning!', messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG, 'warning')
@ -141,7 +144,28 @@ export class NewBallot extends React.Component {
} }
} }
if (!ballotStore.isBallotForKey && !ballotStore.isBallotForMinThreshold && !ballotStore.isBallotForProxy) { if (ballotStore.isBallotForEmissionFunds) {
if (ballotStore.ballotEmissionFunds.receiver.length === 0) {
swal('Warning!', `Address of funds receiver is empty`, 'warning')
commonStore.hideLoading()
return false
}
const isAddress = contractsStore.web3Instance.isAddress(ballotStore.ballotEmissionFunds.receiver)
if (!isAddress) {
swal('Warning!', messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG, 'warning')
commonStore.hideLoading()
return false
}
}
if (
!ballotStore.isBallotForKey &&
!ballotStore.isBallotForMinThreshold &&
!ballotStore.isBallotForProxy &&
!ballotStore.isBallotForEmissionFunds
) {
swal('Warning!', messages.BALLOT_TYPE_IS_EMPTY_MSG, 'warning') swal('Warning!', messages.BALLOT_TYPE_IS_EMPTY_MSG, 'warning')
commonStore.hideLoading() commonStore.hideLoading()
return false return false
@ -150,11 +174,11 @@ export class NewBallot extends React.Component {
return true return true
} }
createBallotForKeys = startTime => { createBallotForKeys = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props const { ballotStore, contractsStore } = this.props
const inputToMethod = { const inputToMethod = {
startTime: startTime, startTime: startTime,
endTime: ballotStore.endTimeUnix, endTime: endTime,
affectedKey: ballotStore.ballotKeys.affectedKey, affectedKey: ballotStore.ballotKeys.affectedKey,
affectedKeyType: ballotStore.ballotKeys.keyType, affectedKeyType: ballotStore.ballotKeys.keyType,
newVotingKey: ballotStore.ballotKeys.newVotingKey, newVotingKey: ballotStore.ballotKeys.newVotingKey,
@ -176,22 +200,22 @@ export class NewBallot extends React.Component {
return data return data
} }
createBallotForMinThreshold = startTime => { createBallotForMinThreshold = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props const { ballotStore, contractsStore } = this.props
const inputToMethod = { const inputToMethod = {
startTime: startTime, startTime: startTime,
endTime: ballotStore.endTimeUnix, endTime: endTime,
proposedValue: ballotStore.ballotMinThreshold.proposedValue, proposedValue: ballotStore.ballotMinThreshold.proposedValue,
memo: ballotStore.memo memo: ballotStore.memo
} }
return contractsStore.votingToChangeMinThreshold.createBallot(inputToMethod) return contractsStore.votingToChangeMinThreshold.createBallot(inputToMethod)
} }
createBallotForProxy = startTime => { createBallotForProxy = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props const { ballotStore, contractsStore } = this.props
const inputToMethod = { const inputToMethod = {
startTime: startTime, startTime: startTime,
endTime: ballotStore.endTimeUnix, endTime: endTime,
proposedValue: ballotStore.ballotProxy.proposedAddress, proposedValue: ballotStore.ballotProxy.proposedAddress,
contractType: ballotStore.ballotProxy.contractType, contractType: ballotStore.ballotProxy.contractType,
memo: ballotStore.memo memo: ballotStore.memo
@ -199,6 +223,17 @@ export class NewBallot extends React.Component {
return contractsStore.votingToChangeProxy.createBallot(inputToMethod) return contractsStore.votingToChangeProxy.createBallot(inputToMethod)
} }
createBallotForEmissionFunds = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props
const inputToMethod = {
startTime: startTime,
endTime: endTime,
receiver: ballotStore.ballotEmissionFunds.receiver,
memo: ballotStore.memo
}
return contractsStore.votingToManageEmissionFunds.createBallot(inputToMethod)
}
onClick = async () => { onClick = async () => {
const { commonStore, contractsStore, ballotStore, ballotsStore } = this.props const { commonStore, contractsStore, ballotStore, ballotsStore } = this.props
const { push } = this.props.routing const { push } = this.props.routing
@ -240,6 +275,42 @@ export class NewBallot extends React.Component {
} }
} }
let startTime = this.getStartTimeUnix()
let endTime = ballotStore.endTimeUnix
if (ballotStore.ballotType === ballotStore.BallotType.emissionFunds) {
const votingContract = contractsStore.votingToManageEmissionFunds
let emissionReleaseTime = Number(await votingContract.emissionReleaseTime())
const currentTime = Number(await votingContract.getTime())
if (currentTime > emissionReleaseTime) {
const emissionReleaseThreshold = Number(await votingContract.emissionReleaseThreshold())
const diff = Math.floor((currentTime - emissionReleaseTime) / emissionReleaseThreshold)
if (diff > 0) {
emissionReleaseTime += emissionReleaseThreshold * diff
}
}
if (currentTime < emissionReleaseTime) {
const emissionReleaseTimeString = moment
.unix(emissionReleaseTime)
.utc()
.format('MMM Do YYYY, h:mm:ss a')
swal('Warning!', messages.EMISSION_RELEASE_TIME_IN_FUTURE(emissionReleaseTimeString), 'warning')
return
}
const noActiveBallotExists = await votingContract.noActiveBallotExists()
if (!noActiveBallotExists) {
swal('Warning!', messages.PREVIOUS_BALLOT_NOT_FINALIZED, 'warning')
return
}
const distributionThreshold = Number(await votingContract.distributionThreshold())
startTime = currentTime + constants.startTimeOffsetInMinutes * 60
endTime = emissionReleaseTime + distributionThreshold
}
let methodToCreateBallot let methodToCreateBallot
let contractType let contractType
let contractInstance let contractInstance
@ -259,16 +330,19 @@ export class NewBallot extends React.Component {
contractType = 'votingToChangeProxy' contractType = 'votingToChangeProxy'
contractInstance = contractsStore.votingToChangeProxy.votingToChangeProxyInstance contractInstance = contractsStore.votingToChangeProxy.votingToChangeProxyInstance
break break
case ballotStore.BallotType.emissionFunds:
methodToCreateBallot = this.createBallotForEmissionFunds
contractType = 'votingToManageEmissionFunds'
contractInstance = contractsStore.votingToManageEmissionFunds.instance
break
default: default:
break break
} }
const startTime = this.getStartTimeUnix()
sendTransactionByVotingKey( sendTransactionByVotingKey(
this.props, this.props,
contractInstance.options.address, contractInstance.options.address,
methodToCreateBallot(startTime), methodToCreateBallot(startTime, endTime),
async tx => { async tx => {
const events = await contractInstance.getPastEvents('BallotCreated', { const events = await contractInstance.getPastEvents('BallotCreated', {
fromBlock: tx.blockNumber, fromBlock: tx.blockNumber,
@ -322,9 +396,23 @@ export class NewBallot extends React.Component {
metadata = <BallotProxyMetadata /> metadata = <BallotProxyMetadata />
minThreshold = contractsStore.proxyBallotThreshold minThreshold = contractsStore.proxyBallotThreshold
break break
case ballotStore.BallotType.emissionFunds:
metadata = <BallotEmissionFundsMetadata />
minThreshold = contractsStore.emissionFundsBallotThreshold
break
default: default:
break break
} }
const emissionFundsManagementBallot = contractsStore.votingToManageEmissionFunds ? (
<div
className={this.menuItemActive(ballotStore.BallotType.emissionFunds)}
onClick={e => ballotStore.changeBallotType(e, ballotStore.BallotType.emissionFunds)}
>
Emission Funds Ballot
</div>
) : (
''
)
return ( return (
<section className="container new"> <section className="container new">
<form action="" className="new-form"> <form action="" className="new-form">
@ -348,12 +436,13 @@ export class NewBallot extends React.Component {
> >
Modify Proxy Contract Ballot Modify Proxy Contract Ballot
</div> </div>
{emissionFundsManagementBallot}
</div> </div>
<div className="info"> <div className="info">
<p className="info-title">Information of the ballot</p> <p className="info-title">Limits of the ballot</p>
<div className="info-i"> <div className="info-i">
Minimum {minThreshold} from {contractsStore.validatorsLength} Minimum {minThreshold} from {contractsStore.validatorsLength} validators are required to pass the&nbsp;
validators are required to pass the proposal<br /> proposal<br />
</div> </div>
<div className="info-i"> <div className="info-i">
You can create {contractsStore.validatorLimits.keys} ballot(s) for keys<br /> You can create {contractsStore.validatorLimits.keys} ballot(s) for keys<br />

View File

@ -6,11 +6,13 @@ constants.ABIsSources = {
KeysManager: 'KeysManager.abi.json', KeysManager: 'KeysManager.abi.json',
PoaNetworkConsensus: 'PoaNetworkConsensus.abi.json', PoaNetworkConsensus: 'PoaNetworkConsensus.abi.json',
BallotStorage: 'BallotsStorage.abi.json', BallotStorage: 'BallotsStorage.abi.json',
EmissionFunds: 'EmissionFunds.abi.json',
ProxyStorage: 'ProxyStorage.abi.json', ProxyStorage: 'ProxyStorage.abi.json',
ValidatorMetadata: 'ValidatorMetadata.abi.json', ValidatorMetadata: 'ValidatorMetadata.abi.json',
VotingToChangeKeys: 'VotingToChangeKeys.abi.json', VotingToChangeKeys: 'VotingToChangeKeys.abi.json',
VotingToChangeMinThreshold: 'VotingToChangeMinThreshold.abi.json', VotingToChangeMinThreshold: 'VotingToChangeMinThreshold.abi.json',
VotingToChangeProxyAddress: 'VotingToChangeProxyAddress.abi.json' VotingToChangeProxyAddress: 'VotingToChangeProxyAddress.abi.json',
VotingToManageEmissionFunds: 'VotingToManageEmissionFunds.abi.json'
} }
constants.NEW_MINING_KEY = { constants.NEW_MINING_KEY = {
label: 'New Mining Key', label: 'New Mining Key',

View File

@ -0,0 +1,15 @@
import Web3 from 'web3'
import { networkAddresses } from './addresses'
export default class EmissionFunds {
async init({ web3, netId }) {
const { EMISSION_FUNDS_ADDRESS } = networkAddresses(netId)
console.log('EmissionFunds address', EMISSION_FUNDS_ADDRESS)
this.web3_10 = new Web3(web3.currentProvider)
this.address = EMISSION_FUNDS_ADDRESS
}
balance() {
return this.web3_10.eth.getBalance(this.address)
}
}

View File

@ -0,0 +1,84 @@
import Web3 from 'web3'
import { networkAddresses } from './addresses'
import helpers from './helpers'
export default class VotingToManageEmissionFunds {
async init({ web3, netId }) {
const { VOTING_TO_MANAGE_EMISSION_FUNDS_ADDRESS } = networkAddresses(netId)
console.log('VotingToManageEmissionFunds address', VOTING_TO_MANAGE_EMISSION_FUNDS_ADDRESS)
const web3_10 = new Web3(web3.currentProvider)
const branch = helpers.getBranch(netId)
const votingToManageEmissionFundsABI = await helpers.getABI(branch, 'VotingToManageEmissionFunds')
this.instance = new web3_10.eth.Contract(votingToManageEmissionFundsABI, VOTING_TO_MANAGE_EMISSION_FUNDS_ADDRESS)
this.address = VOTING_TO_MANAGE_EMISSION_FUNDS_ADDRESS
}
// setters
cancelNewBallot() {
return this.instance.methods.cancelNewBallot().encodeABI()
}
createBallot({ startTime, endTime, receiver, memo }) {
return this.instance.methods.createBallot(startTime, endTime, receiver, memo).encodeABI()
}
finalize(_id) {
return this.instance.methods.finalize(_id).encodeABI()
}
vote(_id, choice) {
return this.instance.methods.vote(_id, choice).encodeABI()
}
// getters
ballotCancelingThreshold() {
return this.instance.methods.ballotCancelingThreshold().call()
}
canBeFinalizedNow(_id) {
return this.instance.methods.canBeFinalizedNow(_id).call()
}
distributionThreshold() {
return this.instance.methods.distributionThreshold().call()
}
emissionReleaseThreshold() {
return this.instance.methods.emissionReleaseThreshold().call()
}
emissionReleaseTime() {
return this.instance.methods.emissionReleaseTime().call()
}
getBallotInfo(_id, _votingKey) {
return this.instance.methods.getBallotInfo(_id).call()
}
getTime() {
return this.instance.methods.getTime().call()
}
hasAlreadyVoted(_id, _votingKey) {
return this.instance.methods.hasAlreadyVoted(_id, _votingKey).call()
}
isActive(_id) {
return this.instance.methods.isActive(_id).call()
}
isValidVote(_id, _votingKey) {
return this.instance.methods.isValidVote(_id, _votingKey).call()
}
nextBallotId() {
return this.instance.methods.nextBallotId().call()
}
noActiveBallotExists() {
return this.instance.methods.noActiveBallotExists().call()
}
}

View File

@ -49,7 +49,7 @@ class AppMainRouter extends Component {
let setVotingToChangeProxy = contractsStore.setVotingToChangeProxy(web3Config) let setVotingToChangeProxy = contractsStore.setVotingToChangeProxy(web3Config)
let setValidatorMetadata = contractsStore.setValidatorMetadata(web3Config) let setValidatorMetadata = contractsStore.setValidatorMetadata(web3Config)
await Promise.all([ let promises = [
setPoaConsensus, setPoaConsensus,
setBallotsStorage, setBallotsStorage,
setKeysManager, setKeysManager,
@ -58,7 +58,15 @@ class AppMainRouter extends Component {
setVotingToChangeMinThreshold, setVotingToChangeMinThreshold,
setVotingToChangeProxy, setVotingToChangeProxy,
setValidatorMetadata setValidatorMetadata
]) ]
if (web3Config.netId === '77') {
// if we're in Sokol
promises.push(contractsStore.setEmissionFunds(web3Config))
promises.push(contractsStore.setVotingToManageEmissionFunds(web3Config))
}
await Promise.all(promises)
await contractsStore.setMiningKey(web3Config) await contractsStore.setMiningKey(web3Config)
await contractsStore.setVotingKey(web3Config) await contractsStore.setVotingKey(web3Config)
@ -67,7 +75,6 @@ class AppMainRouter extends Component {
await contractsStore.getAllBallots() await contractsStore.getAllBallots()
contractsStore.getKeysBallotThreshold() contractsStore.getKeysBallotThreshold()
contractsStore.getMinThresholdBallotThreshold()
contractsStore.getProxyBallotThreshold() contractsStore.getProxyBallotThreshold()
contractsStore.getBallotsLimits() contractsStore.getBallotsLimits()
console.log('votingKey', contractsStore.votingKey) console.log('votingKey', contractsStore.votingKey)

View File

@ -10,7 +10,7 @@ messages.INVALID_VOTE_MSG = "You can't vote on this ballot"
messages.INVALID_FINALIZE_MSG = "You can't finalize this ballot" messages.INVALID_FINALIZE_MSG = "You can't finalize this ballot"
messages.AFFECTED_KEY_IS_NOT_ADDRESS_MSG = "Ballot affectedKey isn't address" messages.AFFECTED_KEY_IS_NOT_ADDRESS_MSG = "Ballot affectedKey isn't address"
messages.MINING_KEY_IS_NOT_ADDRESS_MSG = "Ballot miningKey isn't address" messages.MINING_KEY_IS_NOT_ADDRESS_MSG = "Ballot miningKey isn't address"
messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG = "Ballot proposedAddress isn't address" messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG = "Proposed address isn't address"
messages.END_TIME_SHOULD_BE_GREATER_THAN_NOW_MSG = 'Ballot end time should be greater than now' messages.END_TIME_SHOULD_BE_GREATER_THAN_NOW_MSG = 'Ballot end time should be greater than now'
messages.BALLOT_TYPE_IS_EMPTY_MSG = 'Ballot type is empty' messages.BALLOT_TYPE_IS_EMPTY_MSG = 'Ballot type is empty'
messages.NO_METAMASK_MSG = `You haven't chosen any account in MetaMask. messages.NO_METAMASK_MSG = `You haven't chosen any account in MetaMask.
@ -30,6 +30,10 @@ messages.SHOULD_BE_MORE_THAN_MIN_DURATION = (minDuration, duration, neededHours,
messages.SHOULD_BE_LESS_OR_EQUAL_14_DAYS = duration => { messages.SHOULD_BE_LESS_OR_EQUAL_14_DAYS = duration => {
return `Ballot end time should not be more than 14 days from now in UTC time. Current duration is ${duration} hours.` return `Ballot end time should not be more than 14 days from now in UTC time. Current duration is ${duration} hours.`
} }
messages.EMISSION_RELEASE_TIME_IN_FUTURE = emissionReleaseTime => {
return `You cannot create ballot right now. You'll be able to do that after ${emissionReleaseTime} UTC.`
}
messages.PREVIOUS_BALLOT_NOT_FINALIZED = 'Previous ballot should be finalized first.'
messages.BALLOT_CREATE_FAILED_TX = `Your transaction was failed. Please make sure you set correct parameters for ballot creation. messages.BALLOT_CREATE_FAILED_TX = `Your transaction was failed. Please make sure you set correct parameters for ballot creation.
Make sure you don't have Transaction Error. Exception thrown in contract code message in Metamask before you sign it.` Make sure you don't have Transaction Error. Exception thrown in contract code message in Metamask before you sign it.`
messages.VOTE_FAILED_TX = `Your transaction was failed. Please make sure you haven't already voted for this ballot. messages.VOTE_FAILED_TX = `Your transaction was failed. Please make sure you haven't already voted for this ballot.

View File

@ -6,7 +6,8 @@ class BallotStore {
BallotType = { BallotType = {
keys: 1, keys: 1,
minThreshold: 2, minThreshold: 2,
proxy: 3 proxy: 3,
emissionFunds: 4
} }
KeysBallotType = { KeysBallotType = {
add: 1, add: 1,
@ -34,6 +35,8 @@ class BallotStore {
@observable ballotKeys @observable ballotKeys
@observable ballotMinThreshold @observable ballotMinThreshold
@observable ballotProxy @observable ballotProxy
@observable ballotEmissionFunds
@observable memo @observable memo
constructor() { constructor() {
@ -59,6 +62,11 @@ class BallotStore {
proposedAddress: '', proposedAddress: '',
contractType: '' contractType: ''
} }
this.ballotEmissionFunds = {
receiver: ''
}
this.memo = '' this.memo = ''
} }
@ -83,6 +91,11 @@ class BallotStore {
return this.ballotType === this.BallotType.proxy return this.ballotType === this.BallotType.proxy
} }
@computed
get isBallotForEmissionFunds() {
return this.ballotType === this.BallotType.emissionFunds
}
@computed @computed
get isAddKeysBallotType() { get isAddKeysBallotType() {
return this.ballotKeys.keysBallotType === this.KeysBallotType.add return this.ballotKeys.keysBallotType === this.KeysBallotType.add

View File

@ -1,21 +1,9 @@
import { observable } from 'mobx' import { observable } from 'mobx'
class BallotsStore { class BallotsStore {
@observable activeKeysBallotsLength
@observable activeMinThresholdBallotsLength
@observable activeProxyBallotsLength
@observable ballotCards @observable ballotCards
@observable activeMinThresholdBallotsIDs
@observable activeProxyBallotsIDs
constructor() { constructor() {
this.activeKeysBallotsLength = 0
this.activeMinThresholdBallotsLength = 0
this.activeProxyBallotsLength = 0
this.activeMinThresholdBallotsIDs = []
this.activeProxyBallotsIDs = []
this.ballotCards = [] this.ballotCards = []
} }
} }

View File

@ -3,11 +3,13 @@ import React from 'react'
import PoaConsensus from '../contracts/PoaConsensus.contract' import PoaConsensus from '../contracts/PoaConsensus.contract'
import BallotsStorage from '../contracts/BallotsStorage.contract' import BallotsStorage from '../contracts/BallotsStorage.contract'
import EmissionFunds from '../contracts/EmissionFunds.contract'
import KeysManager from '../contracts/KeysManager.contract' import KeysManager from '../contracts/KeysManager.contract'
import ProxyStorage from '../contracts/ProxyStorage.contract' import ProxyStorage from '../contracts/ProxyStorage.contract'
import VotingToChangeKeys from '../contracts/VotingToChangeKeys.contract' import VotingToChangeKeys from '../contracts/VotingToChangeKeys.contract'
import VotingToChangeMinThreshold from '../contracts/VotingToChangeMinThreshold.contract' import VotingToChangeMinThreshold from '../contracts/VotingToChangeMinThreshold.contract'
import VotingToChangeProxy from '../contracts/VotingToChangeProxy.contract' import VotingToChangeProxy from '../contracts/VotingToChangeProxy.contract'
import VotingToManageEmissionFunds from '../contracts/VotingToManageEmissionFunds.contract'
import ValidatorMetadata from '../contracts/ValidatorMetadata.contract' import ValidatorMetadata from '../contracts/ValidatorMetadata.contract'
import ballotStore from './BallotStore' import ballotStore from './BallotStore'
import ballotsStore from './BallotsStore' import ballotsStore from './BallotsStore'
@ -15,6 +17,7 @@ import commonStore from './CommonStore'
import { BallotKeysCard } from '../components/BallotKeysCard.jsx' import { BallotKeysCard } from '../components/BallotKeysCard.jsx'
import { BallotMinThresholdCard } from '../components/BallotMinThresholdCard.jsx' import { BallotMinThresholdCard } from '../components/BallotMinThresholdCard.jsx'
import { BallotProxyCard } from '../components/BallotProxyCard.jsx' import { BallotProxyCard } from '../components/BallotProxyCard.jsx'
import { BallotEmissionFundsCard } from '../components/BallotEmissionFundsCard.jsx'
import { constants } from '../constants' import { constants } from '../constants'
import 'babel-polyfill' import 'babel-polyfill'
@ -22,11 +25,13 @@ import 'babel-polyfill'
class ContractsStore { class ContractsStore {
@observable poaConsensus @observable poaConsensus
@observable ballotsStorage @observable ballotsStorage
@observable emissionFunds
@observable keysManager @observable keysManager
@observable proxyStorage @observable proxyStorage
@observable votingToChangeKeys @observable votingToChangeKeys
@observable votingToChangeMinThreshold @observable votingToChangeMinThreshold
@observable votingToChangeProxy @observable votingToChangeProxy
@observable votingToManageEmissionFunds
@observable validatorMetadata @observable validatorMetadata
@observable votingKey @observable votingKey
@observable miningKey @observable miningKey
@ -55,18 +60,13 @@ class ContractsStore {
@action('Get keys ballot threshold') @action('Get keys ballot threshold')
getKeysBallotThreshold = async () => { getKeysBallotThreshold = async () => {
this.keysBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods.getBallotThreshold(1).call() this.keysBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods.getBallotThreshold(1).call()
} this.minThresholdBallotThreshold = this.keysBallotThreshold
@action('Get min threshold ballot threshold')
async getMinThresholdBallotThreshold() {
this.minThresholdBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods
.getBallotThreshold(1)
.call()
} }
@action('Get proxy ballot threshold') @action('Get proxy ballot threshold')
getProxyBallotThreshold = async () => { getProxyBallotThreshold = async () => {
this.proxyBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods.getProxyThreshold().call() this.proxyBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods.getProxyThreshold().call()
this.emissionFundsBallotThreshold = this.proxyBallotThreshold
} }
@action('Set web3Instance') @action('Set web3Instance')
@ -93,6 +93,15 @@ class ContractsStore {
}) })
} }
@action('Set EmissionFunds contract')
setEmissionFunds = async web3Config => {
this.emissionFunds = new EmissionFunds()
await this.emissionFunds.init({
web3: web3Config.web3Instance,
netId: web3Config.netId
})
}
@action('Set KeysManager contract') @action('Set KeysManager contract')
setKeysManager = async web3Config => { setKeysManager = async web3Config => {
this.keysManager = new KeysManager() this.keysManager = new KeysManager()
@ -138,6 +147,15 @@ class ContractsStore {
}) })
} }
@action('Set VotingToManageEmissionFunds contract')
setVotingToManageEmissionFunds = async web3Config => {
this.votingToManageEmissionFunds = new VotingToManageEmissionFunds()
await this.votingToManageEmissionFunds.init({
web3: web3Config.web3Instance,
netId: web3Config.netId
})
}
@action('Set ValidatorMetadata contract') @action('Set ValidatorMetadata contract')
setValidatorMetadata = async web3Config => { setValidatorMetadata = async web3Config => {
this.validatorMetadata = new ValidatorMetadata() this.validatorMetadata = new ValidatorMetadata()
@ -171,12 +189,19 @@ class ContractsStore {
getAllBallots = async () => { getAllBallots = async () => {
let keysNextBallotId = 0, let keysNextBallotId = 0,
minThresholdNextBallotId = 0, minThresholdNextBallotId = 0,
proxyNextBallotId = 0 proxyNextBallotId = 0,
emissionFundsNextBallotId = 0
try { try {
;[keysNextBallotId, minThresholdNextBallotId, proxyNextBallotId] = await this.getAllBallotsNextIDs() ;[
keysNextBallotId,
minThresholdNextBallotId,
proxyNextBallotId,
emissionFundsNextBallotId
] = await this.getAllBallotsNextIDs()
keysNextBallotId = Number(keysNextBallotId) keysNextBallotId = Number(keysNextBallotId)
minThresholdNextBallotId = Number(minThresholdNextBallotId) minThresholdNextBallotId = Number(minThresholdNextBallotId)
proxyNextBallotId = Number(proxyNextBallotId) proxyNextBallotId = Number(proxyNextBallotId)
emissionFundsNextBallotId = Number(emissionFundsNextBallotId)
} catch (e) { } catch (e) {
console.log(e.message) console.log(e.message)
} }
@ -184,10 +209,12 @@ class ContractsStore {
const allKeysPromise = this.getCards(keysNextBallotId, 'votingToChangeKeys') const allKeysPromise = this.getCards(keysNextBallotId, 'votingToChangeKeys')
const allMinThresholdPromise = this.getCards(minThresholdNextBallotId, 'votingToChangeMinThreshold') const allMinThresholdPromise = this.getCards(minThresholdNextBallotId, 'votingToChangeMinThreshold')
const allProxyPromise = this.getCards(proxyNextBallotId, 'votingToChangeProxy') const allProxyPromise = this.getCards(proxyNextBallotId, 'votingToChangeProxy')
const allEmissionFundsPromise = this.getCards(emissionFundsNextBallotId, 'votingToManageEmissionFunds')
await Promise.all([allKeysPromise, allMinThresholdPromise, allProxyPromise]) await Promise.all([allKeysPromise, allMinThresholdPromise, allProxyPromise, allEmissionFundsPromise])
const allBallotsIDsLength = keysNextBallotId + minThresholdNextBallotId + proxyNextBallotId const allBallotsIDsLength =
keysNextBallotId + minThresholdNextBallotId + proxyNextBallotId + emissionFundsNextBallotId
if (allBallotsIDsLength === 0) { if (allBallotsIDsLength === 0) {
commonStore.hideLoading() commonStore.hideLoading()
@ -315,6 +342,17 @@ class ContractsStore {
/> />
) )
break break
case 'votingToManageEmissionFunds':
card = (
<BallotEmissionFundsCard
id={id}
type={ballotStore.BallotType.emissionFunds}
key={ballotsStore.ballotCards.length}
pos={ballotsStore.ballotCards.length}
votingState={votingState}
/>
)
break
default: default:
break break
} }
@ -333,7 +371,10 @@ class ContractsStore {
const keysNextBallotId = this.votingToChangeKeys.nextBallotId() const keysNextBallotId = this.votingToChangeKeys.nextBallotId()
const minThresholdNextBallotId = this.votingToChangeMinThreshold.nextBallotId() const minThresholdNextBallotId = this.votingToChangeMinThreshold.nextBallotId()
const proxyNextBallotId = this.votingToChangeProxy.nextBallotId() const proxyNextBallotId = this.votingToChangeProxy.nextBallotId()
return Promise.all([keysNextBallotId, minThresholdNextBallotId, proxyNextBallotId]) const emissionFundsNextBallotId = this.votingToManageEmissionFunds
? this.votingToManageEmissionFunds.nextBallotId()
: 0
return Promise.all([keysNextBallotId, minThresholdNextBallotId, proxyNextBallotId, emissionFundsNextBallotId])
} }
@action @action