Merge pull request #173 from varasev/issue-130

(Feature) Votings to Manage Emission Funds
This commit is contained in:
Vadim Arasev 2018-09-20 13:28:47 +03:00 committed by GitHub
commit 5fdf932a05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 835 additions and 194 deletions

File diff suppressed because one or more lines are too long

View File

@ -136,4 +136,12 @@ button {
padding-top: 12px;
margin: 0;
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 REJECT = 2
const SEND = 1
const BURN = 2
const FREEZE = 3
const USDateTimeFormat = 'MM/DD/YYYY h:mm:ss A'
const maxDetailsLength = 500
@ -16,6 +19,7 @@ const zeroTimeTo = '00:00'
@inject('commonStore', 'contractsStore', 'routing', 'ballotsStore')
@observer
export class BallotCard extends React.Component {
@observable cancelDeadline = 0
@observable startTime
@observable endTime
@observable timeTo = {}
@ -31,39 +35,63 @@ export class BallotCard extends React.Component {
displayValue: zeroTimeTo,
title: 'To close'
}
@observable
timeToCancel = {
val: 0,
displayValue: zeroTimeTo
}
@observable creatorMiningKey
@observable creator
@observable progress
@observable totalVoters
@observable burnVotes
@observable freezeVotes
@observable sendVotes
@observable isFinalized
@observable isCanceled = false
@observable canBeFinalized
@observable hasAlreadyVoted
@observable memo
@computed
get finalizeButtonDisplayName() {
const displayName = this.isFinalized ? 'Finalized' : 'Finalize ballot'
return displayName
}
@computed
get finalizeButtonClass() {
const cls = this.isFinalized
? 'btn btn-primary btn-finalize disabled text-capitalize'
: 'btn btn-primary btn-finalize text-capitalize'
return cls
}
@computed
get finalizeDescription() {
get cancelOrFinalizeButtonDisplayName() {
if (this.isFinalized) {
return 'Finalized'
} else if (this.isCanceled) {
return 'Canceled'
} else if (this.timeToCancel.val > 0) {
return 'Cancel ballot'
} else {
return 'Finalize ballot'
}
}
@computed
get cancelOrFinalizeButtonClass() {
if (this.isFinalized) {
return 'btn btn-primary btn-finalize disabled text-capitalize'
} else if (this.isCanceled) {
return 'btn btn-primary disabled text-capitalize'
} else if (this.timeToCancel.val > 0) {
return 'btn btn-danger text-capitalize'
} else {
return 'btn btn-primary btn-finalize text-capitalize'
}
}
@computed
get cancelOrFinalizeDescription() {
if (this.isFinalized || this.isCanceled) {
return ''
} else if (this.timeToCancel.val > 0) {
return `You can cancel this ballot within ${this.timeToCancel.displayValue}`
} else {
let description = 'Finalization is available after ballot time is finished'
if (this.canBeFinalized !== null) {
description += ' or all validators are voted'
}
return description
}
let description = 'Finalization is available after ballot time is finished'
if (this.canBeFinalized !== null) {
description += ' or all validators are voted'
}
return description
}
@computed
@ -102,21 +130,85 @@ export class BallotCard extends React.Component {
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')
calcTimeTo = () => {
const _now = moment()
const cancel = moment.utc(this.cancelDeadline, USDateTimeFormat)
const start = moment.utc(this.startTime, USDateTimeFormat)
const finish = moment.utc(this.endTime, USDateTimeFormat)
let msStart = start.diff(_now)
let msFinish = finish.diff(_now)
const msCancel = cancel.diff(_now)
const msStart = start.diff(_now)
const msFinish = finish.diff(_now)
if (msStart > 0) {
if (msCancel > 0 && !this.isCanceled) {
this.timeToCancel.val = msCancel
this.timeToCancel.displayValue = this.formatMs(msCancel, ':mm:ss')
} else {
this.timeToCancel.val = 0
this.timeToCancel.displayValue = zeroTimeTo
}
if (msStart > 0 && !this.isCanceled) {
this.timeToStart.val = msStart + 5000
this.timeToStart.displayValue = this.formatMs(msStart, ':mm:ss')
return (this.timeTo = this.timeToStart)
}
if (msFinish > 0) {
if (msFinish > 0 && !this.isCanceled) {
this.timeToStart.val = 0
this.timeToFinish.val = msFinish
this.timeToFinish.displayValue = this.formatMs(msFinish, ':mm:ss')
@ -175,6 +267,10 @@ export class BallotCard extends React.Component {
}
vote = async ({ choice }) => {
if (this.isCanceled) {
swal('Warning!', messages.INVALID_VOTE_MSG, 'warning')
return
}
if (this.timeToStart.val > 0) {
swal('Warning!', messages.ballotIsNotActiveMsg(this.timeTo.displayValue), 'warning')
return
@ -202,9 +298,22 @@ export class BallotCard extends React.Component {
async tx => {
const ballotInfo = await contract.getBallotInfo(id, contractsStore.votingKey)
this.totalVoters = Number(ballotInfo.totalVoters)
this.progress = Number(ballotInfo.progress)
if (ballotInfo.hasOwnProperty('totalVoters')) {
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)
if (ballotInfo.hasOwnProperty('isCanceled')) {
this.isCanceled = Boolean(ballotInfo.isCanceled)
}
if (ballotInfo.hasOwnProperty('canBeFinalizedNow')) {
this.canBeFinalized = Boolean(ballotInfo.canBeFinalizedNow)
} else {
@ -212,9 +321,18 @@ export class BallotCard extends React.Component {
}
this.hasAlreadyVoted = true
ballotsStore.ballotCards[pos].props.votingState.totalVoters = this.totalVoters
ballotsStore.ballotCards[pos].props.votingState.progress = this.progress
if (ballotInfo.hasOwnProperty('totalVoters')) {
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.isCanceled = this.isCanceled
ballotsStore.ballotCards[pos].props.votingState.canBeFinalized = this.canBeFinalized
ballotsStore.ballotCards[pos].props.votingState.hasAlreadyVoted = this.hasAlreadyVoted
@ -226,11 +344,69 @@ export class BallotCard extends React.Component {
)
}
finalize = async e => {
if (this.isFinalized) {
cancelOrFinalize = e => {
if (this.isFinalized || this.isCanceled) {
return
}
if (this.timeToCancel.val > 0) {
this.cancel(e)
} else {
this.finalize(e)
}
}
cancel = async e => {
console.log('cancel function called')
const { votingState, contractsStore, commonStore, ballotsStore, votingType, id, pos } = this.props
const { push } = this.props.routing
const contract = this.getContract(contractsStore, votingType)
let canCancel = true
if (!this.timeToCancel.val) {
canCancel = false
}
if (votingState.creatorMiningKey.toLowerCase() !== contractsStore.miningKey.toLowerCase()) {
canCancel = false
}
commonStore.showLoading()
if (!votingState.creationTime) {
canCancel = false
} else {
const currentTime = Number(await contract.getTime())
if (currentTime - votingState.creationTime > contractsStore.ballotCancelingThreshold) {
canCancel = false
}
}
if (!canCancel) {
commonStore.hideLoading()
swal('Warning!', messages.INVALID_CANCEL_MSG, 'warning')
return
}
sendTransactionByVotingKey(
this.props,
contract.address,
contract.cancelBallot(id),
async tx => {
this.isFinalized = false
this.isCanceled = true
ballotsStore.ballotCards[pos].props.votingState.isFinalized = this.isFinalized
ballotsStore.ballotCards[pos].props.votingState.isCanceled = this.isCanceled
if (this.canBeFinalized !== null) {
this.canBeFinalized = false
ballotsStore.ballotCards[pos].props.votingState.canBeFinalized = this.canBeFinalized
}
swal('Congratulations!', messages.CANCELED_SUCCESS_MSG, 'success').then(result => {
push(`${commonStore.rootPath}`)
})
},
messages.CANCEL_BALLOT_FAILED_TX
)
}
finalize = async e => {
console.log('finalize function called')
if (this.timeToStart.val > 0) {
swal('Warning!', messages.ballotIsNotActiveMsg(this.timeTo.displayValue), 'warning')
return
@ -271,7 +447,9 @@ export class BallotCard extends React.Component {
})
if (events.length > 0) {
this.isFinalized = true
this.isCanceled = false
ballotsStore.ballotCards[pos].props.votingState.isFinalized = this.isFinalized
ballotsStore.ballotCards[pos].props.votingState.isCanceled = this.isCanceled
if (this.canBeFinalized !== null) {
this.canBeFinalized = false
ballotsStore.ballotCards[pos].props.votingState.canBeFinalized = this.canBeFinalized
@ -315,6 +493,8 @@ export class BallotCard extends React.Component {
return contractsStore.votingToChangeMinThreshold
case 'votingToChangeProxy':
return contractsStore.votingToChangeProxy
case 'votingToManageEmissionFunds':
return contractsStore.votingToManageEmissionFunds
case 'validatorMetadata':
return contractsStore.validatorMetadata
default:
@ -330,6 +510,8 @@ export class BallotCard extends React.Component {
return contractsStore.minThresholdBallotThreshold
case 'votingToChangeProxy':
return contractsStore.proxyBallotThreshold
case 'votingToManageEmissionFunds':
return contractsStore.emissionFundsBallotThreshold
default:
return contractsStore.keysBallotThreshold
}
@ -337,22 +519,49 @@ export class BallotCard extends React.Component {
constructor(props) {
super(props)
const { votingState } = this.props
const { votingState, contractsStore } = this.props
// getTimes
if (
votingState.hasOwnProperty('creationTime') &&
contractsStore.ballotCancelingThreshold > 0 &&
votingState.creatorMiningKey === contractsStore.miningKey
) {
votingState.creationTime = Number(votingState.creationTime)
this.cancelDeadline = moment
.utc((votingState.creationTime + contractsStore.ballotCancelingThreshold) * 1000)
.format(USDateTimeFormat)
}
this.startTime = moment.utc(votingState.startTime * 1000).format(USDateTimeFormat)
this.endTime = moment.utc(votingState.endTime * 1000).format(USDateTimeFormat)
this.calcTimeTo()
// getCreator
this.creator = votingState.creator
this.creatorMiningKey = votingState.creatorMiningKey
// 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
this.progress = Number(votingState.progress)
if (votingState.hasOwnProperty('progress')) {
this.progress = Number(votingState.progress)
}
// getIsFinalized
this.isFinalized = votingState.isFinalized
// getIsCanceled
if (votingState.hasOwnProperty('isCanceled')) {
this.isCanceled = votingState.isCanceled
}
this.calcTimeTo()
// canBeFinalizedNow
this.canBeFinalized = votingState.hasOwnProperty('canBeFinalizedNow') ? votingState.canBeFinalizedNow : null
if (votingState.hasOwnProperty('canBeFinalizedNow')) {
this.canBeFinalized = votingState.canBeFinalizedNow
} else {
this.canBeFinalizedNow()
}
// getMemo
this.memo = votingState.memo
// hasAlreadyVoted
@ -383,9 +592,12 @@ export class BallotCard extends React.Component {
showCard = () => {
let { commonStore } = this.props
let checkToFinalizeFilter = commonStore.isToFinalizeFilter
? !this.isFinalized && (this.timeToFinish.val === 0 || this.canBeFinalized) && this.timeToStart.val === 0
? !this.isFinalized &&
!this.isCanceled &&
(this.timeToFinish.val === 0 || this.canBeFinalized) &&
this.timeToStart.val === 0
: true
let show = commonStore.isActiveFilter ? !this.isFinalized : checkToFinalizeFilter
let show = commonStore.isActiveFilter ? !this.isFinalized && !this.isCanceled : checkToFinalizeFilter
return show
}
@ -397,6 +609,8 @@ export class BallotCard extends React.Component {
return 'Keys'
case 'votingToChangeProxy':
return 'Proxy'
case 'votingToManageEmissionFunds':
return 'EmissionFunds'
default:
return ''
}
@ -425,66 +639,25 @@ export class BallotCard extends React.Component {
) : (
''
)
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>
{/* 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>
let votingScale
if (votingType === 'votingToManageEmissionFunds') {
votingScale = (
<div className="ballots-i-scale">
<div className="ballots-i-scale-column ballots-i-scale-column-3">
<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"
>
Burn
</button>
<div className="vote-scale--container">
<p className="vote-scale--votes">{this.votesAgainstNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesAgainstPercents}%</p>
<p className="vote-scale--votes">{this.votesBurnNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesBurnPercents}%</p>
<div className={voteScaleClass}>
<div
className="vote-scale--fill vote-scale--fill_burn"
style={{ width: `${this.votesAgainstPercents}%` }}
style={{ width: `${this.votesBurnPercents}%` }}
/>
</div>
</div>
@ -492,24 +665,45 @@ export class BallotCard extends React.Component {
<div className="ballots-i-scale-column ballots-i-scale-column-3">
<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"
>
Freeze
</button>
<div className="vote-scale--container">
<p className="vote-scale--votes">{this.votesAgainstNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesAgainstPercents}%</p>
<p className="vote-scale--votes">{this.votesFreezeNumber} Votes</p>
<p className="vote-scale--percentage">{this.votesFreezePercents}%</p>
<div className={voteScaleClass}>
<div
className="vote-scale--fill vote-scale--fill_freeze"
style={{ width: `${this.votesAgainstPercents}%` }}
style={{ width: `${this.votesFreezePercents}%` }}
/>
</div>
</div>
</div>
</div> */}
{/* No / yes */}
<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: 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-column">
<button
@ -547,6 +741,33 @@ export class BallotCard extends React.Component {
</button>
</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 info-minimum">
Minimum {threshold} from {contractsStore.validatorsLength} validators are required to pass the proposal
@ -560,10 +781,10 @@ export class BallotCard extends React.Component {
</div>
<div className="ballots-footer">
<div className="ballots-footer-left">
<button type="button" onClick={e => this.finalize(e)} className={this.finalizeButtonClass}>
{this.finalizeButtonDisplayName}
<button type="button" onClick={e => this.cancelOrFinalize(e)} className={this.cancelOrFinalizeButtonClass}>
{this.cancelOrFinalizeButtonDisplayName}
</button>
<p>{this.finalizeDescription}</p>
<p>{this.cancelOrFinalizeDescription}</p>
</div>
{showHasAlreadyVotedLabel}
<div className="ballots-i--vote-label">

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() {
const { 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,117 @@
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 () => {
const { contractsStore } = this.props
this.emissionFundsBalance = 'Loading...'
this.emissionFundsBalance = contractsStore.web3Instance.fromWei(
await contractsStore.emissionFunds.balance(),
'ether'
)
}
@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())
const emissionReleaseThreshold = Number(await votingToManageEmissionFunds.emissionReleaseThreshold())
const currentTime = Number(await votingToManageEmissionFunds.getTime())
const distributionThreshold = Number(await votingToManageEmissionFunds.distributionThreshold())
emissionReleaseTime = votingToManageEmissionFunds.refreshEmissionReleaseTime(
emissionReleaseTime,
emissionReleaseThreshold,
currentTime
)
const releasePlusDistribution = emissionReleaseTime + distributionThreshold
if (currentTime < releasePlusDistribution) {
this.beginDateTime = moment.unix(emissionReleaseTime).format(dateTimeFormat)
this.endDateTime = moment.unix(releasePlusDistribution).format(dateTimeFormat)
} else {
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.poaexplorer.com/address/search/${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 which the funds will be sent to, in case of 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>
{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>
)
}

View File

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

View File

@ -7,6 +7,7 @@ import { KeysTypes } from './KeysTypes.jsx'
import { BallotKeysMetadata } from './BallotKeysMetadata.jsx'
import { BallotMinThresholdMetadata } from './BallotMinThresholdMetadata.jsx'
import { BallotProxyMetadata } from './BallotProxyMetadata.jsx'
import { BallotEmissionFundsMetadata } from './BallotEmissionFundsMetadata.jsx'
import { messages } from '../messages'
import { constants } from '../constants'
import { sendTransactionByVotingKey } from '../helpers'
@ -44,40 +45,42 @@ export class NewBallot extends React.Component {
return false
}
const minBallotDurationInHours = constants.minBallotDurationInDays * 24
const startTime = this.getStartTimeUnix()
const minEndTime = moment
.utc()
.add(minBallotDurationInHours, 'hours')
.format()
let neededMinutes = moment(minEndTime).diff(moment(ballotStore.endTime), 'minutes')
let neededHours = Math.floor(neededMinutes / 60)
let duration = moment.unix(ballotStore.endTimeUnix).diff(moment.unix(startTime), 'hours')
if (!ballotStore.isBallotForEmissionFunds) {
const minBallotDurationInHours = constants.minBallotDurationInDays * 24
const startTime = this.getStartTimeUnix()
const minEndTime = moment
.utc()
.add(minBallotDurationInHours, 'hours')
.format()
let neededMinutes = moment(minEndTime).diff(moment(ballotStore.endTime), 'minutes')
const neededHours = Math.floor(neededMinutes / 60)
let duration = moment.unix(ballotStore.endTimeUnix).diff(moment.unix(startTime), 'hours')
if (duration < 0) {
duration = 0
}
if (duration < 0) {
duration = 0
}
if (neededMinutes > 0) {
neededMinutes = Math.abs(neededHours * 60 - neededMinutes)
swal(
'Warning!',
messages.SHOULD_BE_MORE_THAN_MIN_DURATION(minBallotDurationInHours, duration, neededHours, neededMinutes),
'warning'
)
commonStore.hideLoading()
return false
}
if (neededMinutes > 0) {
neededMinutes = Math.abs(neededHours * 60 - neededMinutes)
swal(
'Warning!',
messages.SHOULD_BE_MORE_THAN_MIN_DURATION(minBallotDurationInHours, duration, neededHours, neededMinutes),
'warning'
)
commonStore.hideLoading()
return false
}
const twoWeeks = moment
.utc()
.add(14, 'days')
.format()
let exceededMinutes = moment(ballotStore.endTime).diff(moment(twoWeeks), 'minutes')
if (exceededMinutes > 0) {
swal('Warning!', messages.SHOULD_BE_LESS_OR_EQUAL_14_DAYS(duration), 'warning')
commonStore.hideLoading()
return false
const twoWeeks = moment
.utc()
.add(14, 'days')
.format()
const exceededMinutes = moment(ballotStore.endTime).diff(moment(twoWeeks), 'minutes')
if (exceededMinutes > 0) {
swal('Warning!', messages.SHOULD_BE_LESS_OR_EQUAL_14_DAYS(duration), 'warning')
commonStore.hideLoading()
return false
}
}
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) {
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')
commonStore.hideLoading()
return false
@ -150,11 +174,11 @@ export class NewBallot extends React.Component {
return true
}
createBallotForKeys = startTime => {
createBallotForKeys = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props
const inputToMethod = {
startTime: startTime,
endTime: ballotStore.endTimeUnix,
startTime,
endTime,
affectedKey: ballotStore.ballotKeys.affectedKey,
affectedKeyType: ballotStore.ballotKeys.keyType,
newVotingKey: ballotStore.ballotKeys.newVotingKey,
@ -176,22 +200,22 @@ export class NewBallot extends React.Component {
return data
}
createBallotForMinThreshold = startTime => {
createBallotForMinThreshold = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props
const inputToMethod = {
startTime: startTime,
endTime: ballotStore.endTimeUnix,
startTime,
endTime,
proposedValue: ballotStore.ballotMinThreshold.proposedValue,
memo: ballotStore.memo
}
return contractsStore.votingToChangeMinThreshold.createBallot(inputToMethod)
}
createBallotForProxy = startTime => {
createBallotForProxy = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props
const inputToMethod = {
startTime: startTime,
endTime: ballotStore.endTimeUnix,
startTime,
endTime,
proposedValue: ballotStore.ballotProxy.proposedAddress,
contractType: ballotStore.ballotProxy.contractType,
memo: ballotStore.memo
@ -199,6 +223,17 @@ export class NewBallot extends React.Component {
return contractsStore.votingToChangeProxy.createBallot(inputToMethod)
}
createBallotForEmissionFunds = (startTime, endTime) => {
const { ballotStore, contractsStore } = this.props
const inputToMethod = {
startTime,
endTime,
receiver: ballotStore.ballotEmissionFunds.receiver,
memo: ballotStore.memo
}
return contractsStore.votingToManageEmissionFunds.createBallot(inputToMethod)
}
onClick = async () => {
const { commonStore, contractsStore, ballotStore, ballotsStore } = this.props
const { push } = this.props.routing
@ -240,6 +275,44 @@ 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 emissionReleaseThreshold = Number(await votingContract.emissionReleaseThreshold())
const currentTime = Number(await votingContract.getTime())
emissionReleaseTime = votingContract.refreshEmissionReleaseTime(
emissionReleaseTime,
emissionReleaseThreshold,
currentTime
)
if (currentTime < emissionReleaseTime) {
commonStore.hideLoading()
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) {
commonStore.hideLoading()
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 contractType
let contractInstance
@ -259,16 +332,19 @@ export class NewBallot extends React.Component {
contractType = 'votingToChangeProxy'
contractInstance = contractsStore.votingToChangeProxy.votingToChangeProxyInstance
break
case ballotStore.BallotType.emissionFunds:
methodToCreateBallot = this.createBallotForEmissionFunds
contractType = 'votingToManageEmissionFunds'
contractInstance = contractsStore.votingToManageEmissionFunds.instance
break
default:
break
}
const startTime = this.getStartTimeUnix()
sendTransactionByVotingKey(
this.props,
contractInstance.options.address,
methodToCreateBallot(startTime),
methodToCreateBallot(startTime, endTime),
async tx => {
const events = await contractInstance.getPastEvents('BallotCreated', {
fromBlock: tx.blockNumber,
@ -322,9 +398,23 @@ export class NewBallot extends React.Component {
metadata = <BallotProxyMetadata />
minThreshold = contractsStore.proxyBallotThreshold
break
case ballotStore.BallotType.emissionFunds:
metadata = <BallotEmissionFundsMetadata />
minThreshold = contractsStore.emissionFundsBallotThreshold
break
default:
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 (
<section className="container new">
<form action="" className="new-form">
@ -348,12 +438,13 @@ export class NewBallot extends React.Component {
>
Modify Proxy Contract Ballot
</div>
{emissionFundsManagementBallot}
</div>
<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">
Minimum {minThreshold} from {contractsStore.validatorsLength}
validators are required to pass the proposal<br />
Minimum {minThreshold} from {contractsStore.validatorsLength} validators are required to pass the&nbsp;
proposal<br />
</div>
<div className="info-i">
You can create {contractsStore.validatorLimits.keys} ballot(s) for keys<br />

View File

@ -6,11 +6,13 @@ constants.ABIsSources = {
KeysManager: 'KeysManager.abi.json',
PoaNetworkConsensus: 'PoaNetworkConsensus.abi.json',
BallotStorage: 'BallotsStorage.abi.json',
EmissionFunds: 'EmissionFunds.abi.json',
ProxyStorage: 'ProxyStorage.abi.json',
ValidatorMetadata: 'ValidatorMetadata.abi.json',
VotingToChangeKeys: 'VotingToChangeKeys.abi.json',
VotingToChangeMinThreshold: 'VotingToChangeMinThreshold.abi.json',
VotingToChangeProxyAddress: 'VotingToChangeProxyAddress.abi.json'
VotingToChangeProxyAddress: 'VotingToChangeProxyAddress.abi.json',
VotingToManageEmissionFunds: 'VotingToManageEmissionFunds.abi.json'
}
constants.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,95 @@
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
cancelBallot(_id) {
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()
}
refreshEmissionReleaseTime(emissionReleaseTime, emissionReleaseThreshold, currentTime) {
let emissionReleaseTimeRefreshed = emissionReleaseTime
if (currentTime > emissionReleaseTime) {
const diff = Math.floor((currentTime - emissionReleaseTime) / emissionReleaseThreshold)
if (diff > 0) {
emissionReleaseTimeRefreshed += emissionReleaseThreshold * diff
}
}
return emissionReleaseTimeRefreshed
}
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 setValidatorMetadata = contractsStore.setValidatorMetadata(web3Config)
await Promise.all([
let promises = [
setPoaConsensus,
setBallotsStorage,
setKeysManager,
@ -58,20 +58,30 @@ class AppMainRouter extends Component {
setVotingToChangeMinThreshold,
setVotingToChangeProxy,
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.setVotingKey(web3Config)
contractsStore.getKeysBallotThreshold()
contractsStore.getProxyBallotThreshold()
contractsStore.getBallotCancelingThreshold()
contractsStore.getBallotsLimits()
await contractsStore.getAllValidatorMetadata()
await contractsStore.getAllBallots()
contractsStore.getKeysBallotThreshold()
contractsStore.getMinThresholdBallotThreshold()
contractsStore.getProxyBallotThreshold()
contractsStore.getBallotsLimits()
console.log('votingKey', contractsStore.votingKey)
console.log('miningKey', contractsStore.miningKey)
commonStore.hideLoading()
})
.catch(error => {

View File

@ -5,12 +5,14 @@ messages.invalidVotingKeyMsg = key => {
messages.VOTED_SUCCESS_MSG = 'You successfully voted'
messages.BALLOT_CREATED_SUCCESS_MSG = 'You successfully created a new ballot'
messages.FINALIZED_SUCCESS_MSG = 'You successfully finalized'
messages.CANCELED_SUCCESS_MSG = 'You successfully canceled'
messages.ALREADY_FINALIZED_MSG = 'This ballot is already finalized'
messages.INVALID_VOTE_MSG = "You can't vote on this ballot"
messages.INVALID_FINALIZE_MSG = "You can't finalize this ballot"
messages.INVALID_CANCEL_MSG = "You can't cancel this ballot"
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.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.BALLOT_TYPE_IS_EMPTY_MSG = 'Ballot type is empty'
messages.NO_METAMASK_MSG = `You haven't chosen any account in MetaMask.
@ -30,12 +32,18 @@ messages.SHOULD_BE_MORE_THAN_MIN_DURATION = (minDuration, duration, neededHours,
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.`
}
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.
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.
Make sure you don't have Transaction Error. Exception thrown in contract code message in Metamask before you sign it.`
messages.FINALIZE_FAILED_TX = `Your transaction was failed. Make sure you don't have Transaction Error.
Exception thrown in contract code message in Metamask before you sign it.`
messages.CANCEL_BALLOT_FAILED_TX = `Your transaction was failed. Make sure you don't have Transaction Error.
Exception thrown in contract code message in Metamask before you sign it.`
messages.DESCRIPTION_IS_EMPTY = 'Description cannot be empty'
messages.wrongRepo = repo => {
return `There is no contracts.json in configured repo ${repo}`

View File

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

View File

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

View File

@ -3,11 +3,13 @@ import React from 'react'
import PoaConsensus from '../contracts/PoaConsensus.contract'
import BallotsStorage from '../contracts/BallotsStorage.contract'
import EmissionFunds from '../contracts/EmissionFunds.contract'
import KeysManager from '../contracts/KeysManager.contract'
import ProxyStorage from '../contracts/ProxyStorage.contract'
import VotingToChangeKeys from '../contracts/VotingToChangeKeys.contract'
import VotingToChangeMinThreshold from '../contracts/VotingToChangeMinThreshold.contract'
import VotingToChangeProxy from '../contracts/VotingToChangeProxy.contract'
import VotingToManageEmissionFunds from '../contracts/VotingToManageEmissionFunds.contract'
import ValidatorMetadata from '../contracts/ValidatorMetadata.contract'
import ballotStore from './BallotStore'
import ballotsStore from './BallotsStore'
@ -15,6 +17,7 @@ import commonStore from './CommonStore'
import { BallotKeysCard } from '../components/BallotKeysCard.jsx'
import { BallotMinThresholdCard } from '../components/BallotMinThresholdCard.jsx'
import { BallotProxyCard } from '../components/BallotProxyCard.jsx'
import { BallotEmissionFundsCard } from '../components/BallotEmissionFundsCard.jsx'
import { constants } from '../constants'
import 'babel-polyfill'
@ -22,11 +25,13 @@ import 'babel-polyfill'
class ContractsStore {
@observable poaConsensus
@observable ballotsStorage
@observable emissionFunds
@observable keysManager
@observable proxyStorage
@observable votingToChangeKeys
@observable votingToChangeMinThreshold
@observable votingToChangeProxy
@observable votingToManageEmissionFunds
@observable validatorMetadata
@observable votingKey
@observable miningKey
@ -35,6 +40,8 @@ class ContractsStore {
@observable keysBallotThreshold
@observable minThresholdBallotThreshold
@observable proxyBallotThreshold
@observable emissionFundsBallotThreshold
@observable ballotCancelingThreshold
@observable validatorLimits
@observable validatorsMetadata
@observable netId
@ -55,18 +62,20 @@ class ContractsStore {
@action('Get keys ballot threshold')
getKeysBallotThreshold = async () => {
this.keysBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods.getBallotThreshold(1).call()
}
@action('Get min threshold ballot threshold')
async getMinThresholdBallotThreshold() {
this.minThresholdBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.methods
.getBallotThreshold(1)
.call()
this.minThresholdBallotThreshold = this.keysBallotThreshold
}
@action('Get proxy ballot threshold')
getProxyBallotThreshold = async () => {
this.proxyBallotThreshold = await this.ballotsStorage.ballotsStorageInstance.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')
@ -93,6 +102,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')
setKeysManager = async web3Config => {
this.keysManager = new KeysManager()
@ -138,6 +156,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')
setValidatorMetadata = async web3Config => {
this.validatorMetadata = new ValidatorMetadata()
@ -171,12 +198,19 @@ class ContractsStore {
getAllBallots = async () => {
let keysNextBallotId = 0,
minThresholdNextBallotId = 0,
proxyNextBallotId = 0
proxyNextBallotId = 0,
emissionFundsNextBallotId = 0
try {
;[keysNextBallotId, minThresholdNextBallotId, proxyNextBallotId] = await this.getAllBallotsNextIDs()
;[
keysNextBallotId,
minThresholdNextBallotId,
proxyNextBallotId,
emissionFundsNextBallotId
] = await this.getAllBallotsNextIDs()
keysNextBallotId = Number(keysNextBallotId)
minThresholdNextBallotId = Number(minThresholdNextBallotId)
proxyNextBallotId = Number(proxyNextBallotId)
emissionFundsNextBallotId = Number(emissionFundsNextBallotId)
} catch (e) {
console.log(e.message)
}
@ -184,10 +218,12 @@ class ContractsStore {
const allKeysPromise = this.getCards(keysNextBallotId, 'votingToChangeKeys')
const allMinThresholdPromise = this.getCards(minThresholdNextBallotId, 'votingToChangeMinThreshold')
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) {
commonStore.hideLoading()
@ -315,6 +351,17 @@ class ContractsStore {
/>
)
break
case 'votingToManageEmissionFunds':
card = (
<BallotEmissionFundsCard
id={id}
type={ballotStore.BallotType.emissionFunds}
key={ballotsStore.ballotCards.length}
pos={ballotsStore.ballotCards.length}
votingState={votingState}
/>
)
break
default:
break
}
@ -333,7 +380,10 @@ class ContractsStore {
const keysNextBallotId = this.votingToChangeKeys.nextBallotId()
const minThresholdNextBallotId = this.votingToChangeMinThreshold.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