Check tokens when creating polls and votes (#53)

This commit is contained in:
Szymon Szlachtowicz 2021-09-06 11:34:42 +02:00 committed by GitHub
parent d51b69a6a1
commit d7cefb522b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 27 deletions

View File

@ -16,6 +16,13 @@ const ABI = [
'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)', 'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)',
] ]
export enum MESSEGAGE_SENDING_RESULT {
ok = 0,
notEnoughToken = 1,
errorCreatingMessage = 2,
pollNotFound = 3,
}
export class WakuPolling extends WakuVoting { export class WakuPolling extends WakuVoting {
protected multicall: string protected multicall: string
@ -78,8 +85,19 @@ export class WakuPolling extends WakuVoting {
minToken?: BigNumber, minToken?: BigNumber,
endTime?: number endTime?: number
) { ) {
const pollInit = await PollInitMsg.create(signer, question, answers, pollType, this.chainId, minToken, endTime) const address = await signer.getAddress()
await this.sendWakuMessage(this.wakuMessages['pollInit'], pollInit) await this.updateBalances(address)
if (this.addressesBalances[address] && this.addressesBalances[address]?.gt(minToken ?? BigNumber.from(0))) {
const pollInit = await PollInitMsg.create(signer, question, answers, pollType, this.chainId, minToken, endTime)
if (pollInit) {
await this.sendWakuMessage(this.wakuMessages['pollInit'], pollInit)
return MESSEGAGE_SENDING_RESULT.ok
} else {
return MESSEGAGE_SENDING_RESULT.errorCreatingMessage
}
} else {
return MESSEGAGE_SENDING_RESULT.notEnoughToken
}
} }
public async sendTimedPollVote( public async sendTimedPollVote(
@ -88,18 +106,35 @@ export class WakuPolling extends WakuVoting {
selectedAnswer: number, selectedAnswer: number,
tokenAmount?: BigNumber tokenAmount?: BigNumber
) { ) {
const pollVote = await TimedPollVoteMsg.create(signer, pollId, selectedAnswer, this.chainId, tokenAmount) const address = await signer.getAddress()
await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote) const poll = this.wakuMessages['pollInit'].arr.find((poll: PollInitMsg): poll is PollInitMsg => poll.id === pollId)
if (poll) {
await this.updateBalances(address)
if (this.addressesBalances[address] && this.addressesBalances[address]?.gt(poll.minToken ?? BigNumber.from(0))) {
const pollVote = await TimedPollVoteMsg.create(signer, pollId, selectedAnswer, this.chainId, tokenAmount)
if (pollVote) {
await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote)
} else {
return MESSEGAGE_SENDING_RESULT.errorCreatingMessage
}
} else {
return MESSEGAGE_SENDING_RESULT.notEnoughToken
}
} else {
return MESSEGAGE_SENDING_RESULT.pollNotFound
}
} }
protected addressesBalances: { [address: string]: BigNumber } = {} protected addressesBalances: { [address: string]: BigNumber } = {}
protected lastBlockBalances = 0 protected lastBlockBalances = 0
protected async updateBalances() { protected async updateBalances(newAddress?: string) {
const addresses: string[] = [ const addresses: string[] = [
...this.wakuMessages['pollInit'].arr.map((msg) => msg.owner), ...this.wakuMessages['pollInit'].arr.map((msg) => msg.owner),
...this.wakuMessages['pollVote'].arr.map((msg) => msg.voter), ...this.wakuMessages['pollVote'].arr.map((msg) => msg.voter),
] ]
if (newAddress) addresses.push(newAddress)
const addressesToUpdate: { [addr: string]: boolean } = {} const addressesToUpdate: { [addr: string]: boolean } = {}
const addAddressToUpdate = (addr: string) => { const addAddressToUpdate = (addr: string) => {

View File

@ -8,7 +8,7 @@ import styled from 'styled-components'
import { RadioGroup, SmallButton } from '@status-waku-voting/react-components' import { RadioGroup, SmallButton } from '@status-waku-voting/react-components'
import { PollResults } from './PollResults' import { PollResults } from './PollResults'
import { useEthers } from '@usedapp/core' import { useEthers } from '@usedapp/core'
import { Modal } from '@status-waku-voting/react-components'
type PollProps = { type PollProps = {
poll: DetailedTimedPoll poll: DetailedTimedPoll
wakuPolling: WakuPolling | undefined wakuPolling: WakuPolling | undefined
@ -21,6 +21,7 @@ export function Poll({ poll, wakuPolling, signer }: PollProps) {
const [tokenAmount, setTokenAmount] = useState(0) const [tokenAmount, setTokenAmount] = useState(0)
const [address, setAddress] = useState('') const [address, setAddress] = useState('')
const [userInVoters, setUserInVoters] = useState(-1) const [userInVoters, setUserInVoters] = useState(-1)
const [showNotEnoughTokens, setShowNotEnoughTokens] = useState(false)
useEffect(() => { useEffect(() => {
if (signer) { if (signer) {
@ -63,14 +64,17 @@ export function Poll({ poll, wakuPolling, signer }: PollProps) {
{userInVoters < 0 && ( {userInVoters < 0 && (
<SmallButton <SmallButton
disabled={!signer || !account} disabled={!signer || !account}
onClick={() => { onClick={async () => {
if (wakuPolling && signer) { if (wakuPolling && signer) {
wakuPolling.sendTimedPollVote( const result = await wakuPolling.sendTimedPollVote(
signer, signer,
poll.poll.id, poll.poll.id,
selectedAnswer ?? 0, selectedAnswer ?? 0,
poll.poll.pollType === PollType.WEIGHTED ? BigNumber.from(tokenAmount) : undefined poll.poll.pollType === PollType.WEIGHTED ? BigNumber.from(tokenAmount) : undefined
) )
if (result === 1) {
setShowNotEnoughTokens(true)
}
} }
}} }}
> >
@ -78,10 +82,20 @@ export function Poll({ poll, wakuPolling, signer }: PollProps) {
Vote Vote
</SmallButton> </SmallButton>
)} )}
{showNotEnoughTokens && (
<Modal heading={''} setShowModal={setShowNotEnoughTokens}>
<ModalTextWrapper>You don't have enough tokens to vote</ModalTextWrapper>
</Modal>
)}
</PollWrapper> </PollWrapper>
) )
} }
const ModalTextWrapper = styled.div`
text-align: center;
margin: 32px 0;
`
const VotingWrapper = styled.div` const VotingWrapper = styled.div`
margin-top: 40px; margin-top: 40px;
margin-left: 32px; margin-left: 32px;

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react' import React, { ReactNode, useEffect, useState } from 'react'
import { Wallet } from 'ethers' import { Wallet } from 'ethers'
import { JsonRpcSigner } from '@ethersproject/providers' import { JsonRpcSigner } from '@ethersproject/providers'
import styled from 'styled-components' import styled from 'styled-components'
@ -13,6 +13,27 @@ function getLocaleIsoTime(dateTime: Date) {
return newDate.toISOString().slice(0, -8) return newDate.toISOString().slice(0, -8)
} }
type ConfirmScreenProps = {
setShowModal: (val: boolean) => void
children: ReactNode
}
function ConfirmScreen({ children, setShowModal }: ConfirmScreenProps) {
return (
<Confirmation>
<ConfirmationText>{children}</ConfirmationText>
<SmallButton
onClick={(e) => {
e.preventDefault()
setShowModal(false)
}}
>
Close
</SmallButton>
</Confirmation>
)
}
type PollCreationProps = { type PollCreationProps = {
signer: JsonRpcSigner | Wallet signer: JsonRpcSigner | Wallet
wakuPolling: WakuPolling | undefined wakuPolling: WakuPolling | undefined
@ -23,13 +44,14 @@ export function PollCreation({ signer, wakuPolling, setShowPollCreation }: PollC
const [answers, setAnswers] = useState<string[]>(['', '']) const [answers, setAnswers] = useState<string[]>(['', ''])
const [question, setQuestion] = useState('') const [question, setQuestion] = useState('')
const [showCreateConfirmation, setShowCreateConfirmation] = useState(false) const [showCreateConfirmation, setShowCreateConfirmation] = useState(false)
const [showNotEnoughTokens, setShowNotEnoughTokens] = useState(false)
const [selectedType, setSelectedType] = useState(PollType.NON_WEIGHTED) const [selectedType, setSelectedType] = useState(PollType.NON_WEIGHTED)
const [endTimePicker, setEndTimePicker] = useState(new Date(new Date().getTime() + 10000000)) const [endTimePicker, setEndTimePicker] = useState(new Date(new Date().getTime() + 10000000))
return ( return (
<Modal heading="Create a poll" setShowModal={setShowPollCreation}> <Modal heading="Create a poll" setShowModal={setShowPollCreation}>
<NewPollBox> <NewPollBox>
{!showCreateConfirmation && ( {!showCreateConfirmation && !showNotEnoughTokens && (
<PollForm> <PollForm>
<Input <Input
label={'Question or title of the poll'} label={'Question or title of the poll'}
@ -65,7 +87,7 @@ export function PollCreation({ signer, wakuPolling, setShowPollCreation }: PollC
<SmallButton <SmallButton
onClick={async (e) => { onClick={async (e) => {
e.preventDefault() e.preventDefault()
await wakuPolling?.createTimedPoll( const result = await wakuPolling?.createTimedPoll(
signer, signer,
question, question,
answers, answers,
@ -73,7 +95,12 @@ export function PollCreation({ signer, wakuPolling, setShowPollCreation }: PollC
undefined, undefined,
endTimePicker.getTime() endTimePicker.getTime()
) )
setShowCreateConfirmation(true) if (result === 0) {
setShowCreateConfirmation(true)
}
if (result === 1) {
setShowNotEnoughTokens(true)
}
}} }}
> >
Create a poll Create a poll
@ -82,21 +109,14 @@ export function PollCreation({ signer, wakuPolling, setShowPollCreation }: PollC
)} )}
{showCreateConfirmation && ( {showCreateConfirmation && (
<Confirmation> <ConfirmScreen setShowModal={setShowPollCreation}>
<ConfirmationText> Your poll has been created!
Your poll has been created! <br />
<br /> It will appear at the top of the poll list.
It will appear at the top of the poll list. </ConfirmScreen>
</ConfirmationText> )}
<SmallButton {showNotEnoughTokens && (
onClick={(e) => { <ConfirmScreen setShowModal={setShowPollCreation}>You don't have enough tokens to create poll</ConfirmScreen>
e.preventDefault()
setShowPollCreation(false)
}}
>
Close
</SmallButton>
</Confirmation>
)} )}
</NewPollBox>{' '} </NewPollBox>{' '}
</Modal> </Modal>